package com.asiainfo.dacp.datastash.domain.unit.repos;

import com.asiainfo.dacp.datastash.domain.stepdefine.models.DataStashStepDefine;
import com.asiainfo.dacp.datastash.domain.unit.models.DataStashUnit;
import com.asiainfo.dacp.datastash.domain.unit.models.DataStashUnitStep;
import com.asiainfo.dacp.datastash.orm.dao.core.DataStashStepDefineDao;
import com.asiainfo.dacp.datastash.orm.dao.core.DataStashUnitDao;
import com.asiainfo.dacp.datastash.orm.dao.core.DataStashUnitStepDao;
import com.asiainfo.dacp.datastash.orm.po.core.DataStashStepDefinePo;
import com.asiainfo.dacp.datastash.orm.po.core.DataStashUnitPo;
import com.asiainfo.dacp.datastash.orm.po.core.DataStashUnitStepPo;
import com.asiainfo.dacp.util.BeanConvertUtils;
import com.asiainfo.dacp.util.SimpleKey;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

/**
 * Created by winter on 2017/10/31.
 */
@Repository
public class DataStashUnitRepository {

    @Autowired
    private DataStashUnitDao dataStashUnitDao;

    @Autowired
    private DataStashUnitStepDao dataStashUnitStepDao;
    
    @Autowired
    private DataStashStepDefineDao dataStashStepDefineDao;

    public DataStashUnit findOne(String  unitId){
        DataStashUnitPo po= dataStashUnitDao.findOne(unitId);
        if(po==null){
            return null;
        }
        DataStashUnit unit = BeanConvertUtils.copyBean(po,DataStashUnit.class);
        parseSteps(unit,dataStashUnitStepDao.findListByUnitId(unitId));
        return  unit;
    }

    /**
     * 把平板结构解析成对象
     */
    private void parseSteps(DataStashUnit unit,List<DataStashUnitStepPo> stepPoes){

        Map<String,DataStashUnitStep> stepIndex = new HashMap<>();

        List<DataStashUnitStep> rootSteps = new ArrayList();

        List<DataStashUnitStep> unitSteps = new ArrayList<>();

        List<DataStashStepDefinePo> stepDefineList = dataStashStepDefineDao.findAll();
        Map<String,DataStashStepDefine> stepDefineMap = new HashMap<String,DataStashStepDefine>();
        if(stepDefineList!=null){
            for(DataStashStepDefinePo dataStashStepDefinePo :stepDefineList){
                stepDefineMap.put(dataStashStepDefinePo.getStepInst(), BeanConvertUtils.copyBean(dataStashStepDefinePo,DataStashStepDefine.class));
            }
        }

        for (DataStashUnitStepPo dataStashUnitStepPo :stepPoes){
            DataStashUnitStep dataStashUnitStep = BeanConvertUtils.copyBean(dataStashUnitStepPo,DataStashUnitStep.class);
            dataStashUnitStep.setStepDefine(stepDefineMap.get(dataStashUnitStep.getStepInst()));
            unitSteps.add(dataStashUnitStep);
            stepIndex.put(dataStashUnitStep.getStepIndex(),dataStashUnitStep);
            /*if("-1".equals(dataStashUnitStep.getPreStepIdx()) && StringUtils.isBlank(dataStashUnitStep.getParentStepIdx())){//上级节点为空就是跟节点
                rootSteps.add(dataStashUnitStep);
            }*/
        }

        //处理上级，下级，子，父
        for (DataStashUnitStep dataStashUnitStep : stepIndex.values()){

            if(!"-1".equals(dataStashUnitStep.getPreStepIdx())){//处理上一步骤
                String [] preIdxs = dataStashUnitStep.getPreStepIdx().split(",");
                for (String preIdx :preIdxs){
                    dataStashUnitStep.getPreSteps().add(stepIndex.get(preIdx));
                }
            }

            if(!"-1".equals(dataStashUnitStep.getNextStepIdx())){//处理下一步骤
                String [] nextIdxs= dataStashUnitStep.getNextStepIdx().split(",");
                for (String nextIdx :nextIdxs){
                    dataStashUnitStep.getNextSteps().add(stepIndex.get(nextIdx));
                }
            }

            if(StringUtils.isNotBlank(dataStashUnitStep.getParentStepIdx())){//处理上级
                dataStashUnitStep.setParent(stepIndex.get(dataStashUnitStep.getParentStepIdx()));
                dataStashUnitStep.getParent().getChildren().add(dataStashUnitStep);
            }
        }

        for(DataStashUnitStep dataStashUnitStep : stepIndex.values()){
            if("-1".equals(dataStashUnitStep.getPreStepIdx()) && dataStashUnitStep.getParent()==null){
                rootSteps.add(dataStashUnitStep);
            }
        }

        unit.setStepIndex(stepIndex);
        unit.setRootSteps(rootSteps);
        unit.setUnitSteps(unitSteps);
    }

    public DataStashUnit findByCode(String unitCode)throws  Exception{
        DataStashUnitPo po= dataStashUnitDao.findListByUnitCode(unitCode);
        if(po==null){
            return null;
        }
        DataStashUnit unit = BeanConvertUtils.copyBean(po,DataStashUnit.class);
        parseSteps(unit,dataStashUnitStepDao.findListByUnitId(po.getId()));
        return unit;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public DataStashUnit save(DataStashUnit unit)throws  Exception{
        DataStashUnitPo po = dataStashUnitDao.findOne(unit.getId());
        if(po==null){
            unit.setCreateDt(new Date());
        }
        unit.setLastupd(new Date());

        if(unit.getUnitSteps()!=null&&unit.getUnitSteps().size()>0){
            dataStashUnitStepDao.deleteByUnitId(unit.getId());
            for(DataStashUnitStep step: unit.getUnitSteps()){
                dataStashUnitStepDao.save(BeanConvertUtils.copyBean(step, DataStashUnitStepPo.class));
            }

        }
        dataStashUnitDao.save(BeanConvertUtils.copyBean(unit, DataStashUnitPo.class));
      /*  if(1==1){
            throw new RuntimeException("-====");
        }*/
        return unit;
    }


    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete(String  unitId)throws  Exception{
        dataStashUnitDao.delete(unitId);
        dataStashUnitStepDao.deleteByUnitId(unitId);
    }
    
    public void updateState(String id,String state) {
    	dataStashUnitDao.updateState(id,state);
   }


    public void updateBatchNo(String unitCode,String batchNo){dataStashUnitDao.updateBatchNo(unitCode, batchNo);}

    public Page<DataStashUnit> findAll(int pageSize ,int pageNum , final String unitCode,final String id,final String label,final String  unitType,final String[] state) throws Exception {
        //TODO 增加按创建时间逆序排序
        Pageable pageable = new PageRequest(pageNum, pageSize);
        //TODO 获取对象应该是一个包含字段的丰满对象
        Page<DataStashUnitPo> tablePage = dataStashUnitDao.findAll(new Specification<DataStashUnitPo>() {
            public Predicate toPredicate(Root<DataStashUnitPo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //TODO 增加过滤条件
                List<Predicate> predicate = new ArrayList<Predicate>();
                Predicate[] p = new Predicate[predicate.size()];
                if (StringUtils.isNotBlank(unitCode)) {
                    predicate.add(cb.like(root.get("unitCode").as(String.class), "%" + unitCode + "%"));
                }
                if (StringUtils.isNotBlank(label)) {
                    predicate.add(cb.like(root.get("unitCode").as(String.class), "%" + label + "%"));
                }
                if (StringUtils.isNotBlank(id)) {
                    predicate.add(cb.equal(root.get("id").as(String.class), id));
                }
                if (StringUtils.isNotBlank(unitType)) {
                    predicate.add(cb.equal(root.get("unitType").as(String.class), unitType));
                }
                if (state!=null&&state.length>0) {
                    List<Predicate> predicate3 = new ArrayList<Predicate>();
                    for(int i=0;i<state.length;i++) {
                        predicate3.add(cb.equal(root.get("state").as(String.class), state[i]));
                    }
                    Predicate[] p3 = new Predicate[predicate3.size()];
                    predicate.add(cb.or(predicate3.toArray(p3)));
                }
                query.where(cb.and(predicate.toArray(p)));
                return query.getRestriction();
            }
        }, pageable);
        List<DataStashUnit> list = new ArrayList<DataStashUnit>();
        Iterator<DataStashUnitPo> iter = tablePage.iterator();
        while (iter.hasNext()) {
            DataStashUnitPo po = iter.next();
            DataStashUnit unit = BeanConvertUtils.copyBean(po, DataStashUnit.class);
            parseSteps(unit,dataStashUnitStepDao.findListByUnitId(po.getId()));
            list.add(unit);
        }
        Page<DataStashUnit> page = new PageImpl<DataStashUnit>(list, pageable, tablePage.getTotalElements());
        return page;
    }
    
    public List<DataStashUnit> findAll(){
    	
        List<DataStashUnitPo> unitPoList = dataStashUnitDao.findAll();
    	List<DataStashUnit> list = new ArrayList<DataStashUnit>();
        if(unitPoList!=null){
            for(DataStashUnitPo dataStashUnitPo :unitPoList){
                DataStashUnit dataStashUnit = BeanConvertUtils.copyBean(dataStashUnitPo, DataStashUnit.class);
                parseSteps(dataStashUnit,dataStashUnitStepDao.findListByUnitId(dataStashUnitPo.getId()));
                list.add(dataStashUnit);
            }
        }
       return list;
    }
}
